package com.hfut.eeg.common.util;

import com.hfut.eeg.common.component.EEGcache;
import com.hfut.eeg.common.component.EEGfileListener;
import com.hfut.eeg.common.eegParse.EEGFile;
import com.hfut.eeg.common.eegParse.Hdr;
import com.hfut.eeg.service.PatientInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 梁琦
 * @program: eeg
 * @Package com.hfut.eeg.common.util
 * @Description: TODO
 * @date 2019-11-19 18:34
 */
@Component
public class EEGUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(EEGUtil.class);

    //在进行 short向unsigned short转化时，需要用到
    private static final int USHORT= (int)Math.pow(2, 16);

    //进行char向uchar转化时用到
    private static  final int UCHAR = (int)Math.pow(2, 8);

    //地址分割符,win
    private static final char separatorTag= '\\';


    private  static EEGfileListener listener;


    private static PatientInfoService service;

    private static EEGcache eeGcache;

    //目的在于对静态组件实现注入
    @Autowired
    public void setListener(EEGfileListener listener) {
        EEGUtil.listener = listener;
    }

    @Autowired
    public void setService(PatientInfoService service) {
        EEGUtil.service = service;
    }

    @Autowired
    public  void setEeGcache(EEGcache eeGcache) {
        EEGUtil.eeGcache = eeGcache;
    }

    /**
    * 将文件名进行解析，存储到EEGFile结构体重
    */
    public static EEGFile transformFileName(String fileName){
        EEGFile file = new EEGFile();
        //判断文件是否为空或是否包含后缀
        if(fileName==null || !fileName.contains(".")){
            LOGGER.warn("EEGFile:文件名为空或者不包含后缀名");
            return null;
        }
        //文件最后一个分割点的位置
        int se = fileName.lastIndexOf(".");
        String[] extAndPath = new String[2];
        extAndPath[0] = fileName.substring(0,se);
        extAndPath[1] = fileName.substring(se);
        System.out.println(fileName.indexOf("."));
        //判断路径是否有问题
        if(extAndPath.length>2){
            LOGGER.warn("EEGFile:请解决文件路径包含.字符问题！");
            return null;
        }
        //设置属性值
        file.setExt(extAndPath[1]);
        String pathAndName = extAndPath[0];
        int separatorIndex = pathAndName.lastIndexOf(separatorTag);
        file.setName(pathAndName.substring(separatorIndex+1));
        file.setPath(pathAndName.substring(0,separatorIndex));
        return file;
    }

    /**
    * 设置分隔符
    */
    public String getSeparatorTag(){
        return String.valueOf(separatorTag);
    }

    //进入之前应该先定位光标
    //对应matlab中uint8=>double默认读取方式
    public static Double[] readUnsignedBytes(RandomAccessFile file,int length){
        Double[] result = new Double[length];
        for (int i=0;i<length;i++){
            try {
                result[i] = (double) file.readUnsignedByte();
            } catch (IOException e) {
                LOGGER.warn("readUnsignedBytes: IO错误");
                e.printStackTrace();
            }
        }
        return result;
    }

    /** 在下面所有的转换函数中，均需要采用小端的方式读取，
     * 由于Java是默认采用大端的方式采集数据，所以需要进行转换：
     * 采用nio：按照小端的方式读取字节流
     * ByteBuffer buffer = ByteBuffer.allocate(length*2).order(ByteOrder.LITTLE_ENDIAN);
     * 如果需要处理比如读ushort数据，只需要判断short小于0时，加上2^16即可
     *
     * 注：因为有的转换函数代码是前期所写，实际所用到了只是单字节、或双字节转换，
     * 如果测试多字节处理，可能会有错误，TODO
     */
    //对应matlab中uint8=>uchar读取方式
    public static Integer[] readUcharBytes(RandomAccessFile file,int length){
        Integer[] result = new Integer[length];
        try {
            FileChannel fileChannel = file.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(length).order(ByteOrder.LITTLE_ENDIAN);
            fileChannel.read(buffer);
            buffer.flip();
            buffer.limit(buffer.capacity());
            for (int i=0;i<length;i++){
                result[i] = (int) buffer.get();
                if(result[i]<0){
                    result[i] += UCHAR;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }


    /**
    * 对应matlab中ushort方式
     * Java默认是大端方式！！！！！！！！
    */
    public static Integer[] readShortBytes(RandomAccessFile file, int length) throws Exception {
        Integer[] result = new Integer[length];
        try{
            FileChannel fileChannel = file.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(length*2).order(ByteOrder.LITTLE_ENDIAN);
            fileChannel.read(buffer);
            byte[] tmp = new byte[length*2];
            buffer.flip();
            buffer.limit(buffer.capacity());
            for (int i=0;i<length;i++){
                //进行short到ushort的变换
                result[i]= (int) buffer.getShort();
                if(result[i]<0){
                    result[i] += USHORT;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
    * 对应matlab中Uint32方式
    */
    public static Long[] readUint32Bytes(RandomAccessFile file, int length) throws IOException {
        Long[] result = new Long[length];
        int [] tmp = new int[length*4];
        int num=0;
        //小端转换
        for (int i=tmp.length-1;i>=0;i--){
            //读取文件，同时计算已经读取的字节数量
            if((tmp[i]= file.read())!=-1){
                num++;
            }else {
                break;
            }
        }
        if(num<length*2){
            LOGGER.warn("readShortBytes: 读取字节数量出现问题");
        }
        //参考Java RandomAccessFile readUnsignedShort()源码
        for (int i=0;i<tmp.length/4;i++){
            int ch1 = tmp[i*2];
            int ch2 = tmp[i*2+1];
            int ch3 = tmp[i*2+2];
            int ch4 = tmp[i*2+3];
            if ((ch1 | ch2 | ch3 | ch4) < 0)
                throw new EOFException();
            Long ch = (long) ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
            //result[i]=((long)(ch) << 32) + (ch & 0xFFFFFFFFL);
            result[i] = ch;
        }
        return result;
    }

    public static String detoken(String in,String token){
        if(token==null||"".equals(token)){
            return in;
        }
        //与原算法缺少一段，不过测试好像所有数据都没有经过
        return null;
    }

    public static ArrayList<ArrayList> reShape(Integer[]in, int nchan,
                                               int zeroLevel,ArrayList<Double> eleCode,
                                               double calEEG,double calDC){
        //初始化结果集
        ArrayList<ArrayList> result = new ArrayList<>();
        for (int i=0;i<nchan;i++){
            ArrayList line = new ArrayList();
            result.add(line);
        }

        //证明数据不能完全被分割成nchan*nsample矩阵
        if(in.length%nchan!=0){
            LOGGER.warn("数据不能完全被分割成nchan*nsample矩阵");
        }
        int lines = in.length/nchan;
        for (int i=0;i<lines;i++){
            for(int j=0;j<nchan;j++){
                float tmp = in[i*nchan+j]-zeroLevel;
                if(eleCode.get(j)>=42 && eleCode.get(j)<=73){
                    tmp = (float) (tmp*calDC);
                }else {
                    tmp = (float) (tmp*calEEG);
                }
                result.get(j).add(tmp);
            }
        }
        return result;
    }

    public static boolean checkEEGForPatientById(String Id){
        LOGGER.info("checkEEGForPatientById:"+Id);
        String name =service.getNameById(Id);
        return checkEEGForPatient(name);
    }


    /**
    * @Description: 判断当前监测的eeg文件数据是否是预期病人的数据
    * @param patientName 传入参数为病人编号
    * @return true表示为预期病人，否则不是
    * @author 梁琦
    * @date 2019-12-30 19:58
    * @throws
    */
    public static boolean checkEEGForPatient(String patientName){
        Hdr hdr = listener.getHdr();
        boolean fileChange = listener.isFileStatus();
        //监听到没有文件发生变化，则直接返回false
        if(!fileChange){
            return false;
        }
        String fileEEG = hdr.getOrig().getFileName();
        String PNTname = getNamePNT(fileEEG);
        if(PNTname == null || patientName==null){
            return false;
        }else {
            return patientName.equals(PNTname);
        }
    }

    /**
    * @Description: 判断此时是否应该从EEG文件采集数据，同时设置eegchace的病人ID
    * @param patientID 病人ID
    * @return boolean
    * @author 梁琦
    * @date 2019-12-16 09:14
    * @throws
    */
    public static boolean isCollectData(String patientID){
        if(patientID==null || "".equals(patientID)){
            return false;
        }
        eeGcache.setPatientId(patientID);
        return true;
    }


    /**
    * @Description: 根据EEG文件获取PNT文件，再获取name信息
    * @param fileEEG EEG文件地址
    * @return name 返回为null表示pnt文件没有name值
    * @author 梁琦
    * @date 2019-12-16 08:54
    * @throws
    */
    public static String getNamePNT(String fileEEG) {
        //fileEEG有效性检验
        if(fileEEG==null || fileEEG.lastIndexOf(".")<0){
            LOGGER.error("从PNT获取name失败："+fileEEG);
            return null;
        }
        int index = fileEEG.lastIndexOf(".");
        //获取PNT文件名称
        String filePath = fileEEG.substring(0,index+1)+"PNT";
        StringBuilder builder = new StringBuilder();
        String name = null;
//        HashMap <String,Object> result = new HashMap<>();
        try {
            try(FileInputStream fileInputStream = new FileInputStream(filePath);
                InputStreamReader isr = new InputStreamReader(fileInputStream,"GB2312");
                BufferedReader bufferedReader = new BufferedReader(isr)) {
                String str;
                while ((str=bufferedReader.readLine()) != null){
                    builder.append(str);
                }
                String content = builder.toString().toLowerCase();
                //获取ID
    //            if(content.contains("id")){
    //                int sum =0,start=0;
    //                for (int i=content.indexOf("id")+2;i<content.length();i++){
    //                    if(Character.isLetterOrDigit(content.charAt(i))){
    //                        start=i;
    //                        while (Character.isLetterOrDigit(content.charAt(i))){
    //                            i++;
    //                            sum++;
    //                        }
    //                        break;
    //                    }
    //                }
    //                String id = content.substring(start,start+sum);
    //                result.put("id",id);
    //            }
                //获取姓名
                if(content.contains("name")){
                    int sum =0,start=0;
                    for (int i=content.indexOf("name")+2;i<content.length();i++){
                        if(content.charAt(i)>= 0x4E00 && content.charAt(i)<= 0x9FA5){
                            start =i;
                            while (content.charAt(i)>= 0x4E00 && content.charAt(i)<= 0x9FA5){
                                i++;
                                sum++;
                            }
                            break;
                        }
                    }
                    name = content.substring(start,start+sum);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return name;
    }



    /**
    * 获取分段数据
     * 当num为<0时表示获取所有数据
    */
    public static ArrayList<ArrayList> getSimpleEEGBySeg(Object o,int start,int num){
        ArrayList<ArrayList> tmp = BlobListTrans.transEEGTransToList(o);
        if(tmp==null){
            return null;
        }
        if(num<0){
            return tmp;
        }
        int len = tmp.get(0).size()<start+num?tmp.get(0).size():start+num;
        if(start>tmp.get(0).size()){
            return null;
        }
        ArrayList<ArrayList> result = new ArrayList<>();
        for (ArrayList list : tmp) {
            result.add(new ArrayList(list.subList(start, len)));
        }
        return result;
    }

    /**
    * 实现数组的深度拷贝
    */
    public static ArrayList<ArrayList> deepCopy(ArrayList<ArrayList> lists){
        ArrayList<ArrayList> result = new ArrayList<>();
        for (ArrayList list : lists) {
            List tmp = CollectionUtils.arrayToList(Arrays.copyOfRange(list.toArray(), 0, list.size()));
            result.add(new ArrayList(tmp));
        }
        return result;
    }

    public static ArrayList listBrainChannel(ArrayList<ArrayList> brainChannels){
        if(brainChannels==null||brainChannels.size()==0){
            return null;
        }
        ArrayList result = new ArrayList();
        for (ArrayList list:brainChannels){
            int sum = 0;
            for (int i=0;i<list.size();i++){
                sum += (Integer) list.get(i);
            }
            result.add(sum);
        }
        return result;
    }




    public static void main(String[] args) {
        EEGUtil.checkEEGForPatient("张三");
    }


}
